#ifndef _WX_RICHTEXTBUFFER_H_
#define _WX_RICHTEXTBUFFER_H_

#include "wx/defs.h"
#include "wx/list.h"
#include "wx/textctrl.h"
#include "wx/bitmap.h"
#include "wx/image.h"
#include "wx/cmdproc.h"
#include "wx/txtstrm.h"

#if wxUSE_DATAOBJ
#include "wx/dataobj.h"
#endif

#if defined(__WXGTK__) || (defined(wxMAC_USE_CORE_GRAPHICS) && wxMAC_USE_CORE_GRAPHICS)
#define wxRICHTEXT_USE_OWN_CARET 1
#else
#define wxRICHTEXT_USE_OWN_CARET 0
#endif
#define wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 0

extern const wxChar wxRichTextLineBreakChar;

#define wxRICHTEXT_TYPE_ANY             0
#define wxRICHTEXT_TYPE_TEXT            1
#define wxRICHTEXT_TYPE_XML             2
#define wxRICHTEXT_TYPE_HTML            3
#define wxRICHTEXT_TYPE_RTF             4
#define wxRICHTEXT_TYPE_PDF             5

class wxRichTextCtrl;
class wxRichTextObject;
class wxRichTextCacheObject;
class wxRichTextObjectList;
class wxRichTextLine;
class wxRichTextParagraph;
class wxRichTextFileHandler;
class wxRichTextStyleSheet;
class wxTextAttrEx;
class wxRichTextListStyleDefinition;
class wxRichTextEvent;
class wxRichTextRenderer;
class wxRichTextBuffer;

#define wxRICHTEXT_FIXED_WIDTH      0x01
#define wxRICHTEXT_FIXED_HEIGHT     0x02
#define wxRICHTEXT_VARIABLE_WIDTH   0x04
#define wxRICHTEXT_VARIABLE_HEIGHT  0x08

#define wxRICHTEXT_LAYOUT_SPECIFIED_RECT 0x10

#define wxRICHTEXT_DRAW_IGNORE_CACHE    0x01

#define wxRICHTEXT_HITTEST_NONE     0x01
#define wxRICHTEXT_HITTEST_BEFORE   0x02
#define wxRICHTEXT_HITTEST_AFTER    0x04
#define wxRICHTEXT_HITTEST_ON       0x08
#define wxRICHTEXT_HITTEST_OUTSIDE  0x10

#define wxRICHTEXT_FORMATTED        0x01
#define wxRICHTEXT_UNFORMATTED      0x02
#define wxRICHTEXT_CACHE_SIZE       0x04
#define wxRICHTEXT_HEIGHT_ONLY      0x08

#define wxRICHTEXT_SETSTYLE_NONE            0x00
#define wxRICHTEXT_SETSTYLE_WITH_UNDO       0x01
#define wxRICHTEXT_SETSTYLE_OPTIMIZE        0x02
#define wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY 0x04
#define wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY 0x08
#define wxRICHTEXT_SETSTYLE_RENUMBER        0x10
#define wxRICHTEXT_SETSTYLE_SPECIFY_LEVEL   0x20
#define wxRICHTEXT_SETSTYLE_RESET           0x40
#define wxRICHTEXT_SETSTYLE_REMOVE          0x80
#define wxRICHTEXT_INSERT_NONE                              0x00
#define wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE     0x01
#define wxRICHTEXT_INSERT_INTERACTIVE                       0x02
#define wxTEXT_ATTR_PARA_SPACING_AFTER      0x00000800
#define wxTEXT_ATTR_PARA_SPACING_BEFORE     0x00001000
#define wxTEXT_ATTR_LINE_SPACING            0x00002000
#define wxTEXT_ATTR_CHARACTER_STYLE_NAME    0x00004000
#define wxTEXT_ATTR_PARAGRAPH_STYLE_NAME    0x00008000
#define wxTEXT_ATTR_LIST_STYLE_NAME         0x00010000
#define wxTEXT_ATTR_BULLET_STYLE            0x00020000
#define wxTEXT_ATTR_BULLET_NUMBER           0x00040000
#define wxTEXT_ATTR_BULLET_TEXT             0x00080000
#define wxTEXT_ATTR_BULLET_NAME             0x00100000
#define wxTEXT_ATTR_URL                     0x00200000
#define wxTEXT_ATTR_PAGE_BREAK              0x00400000
#define wxTEXT_ATTR_EFFECTS                 0x00800000
#define wxTEXT_ATTR_OUTLINE_LEVEL           0x01000000
#define wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE   0x10000000
#define wxTEXT_ATTR_BULLET_STYLE_NONE               0x00000000
#define wxTEXT_ATTR_BULLET_STYLE_ARABIC             0x00000001
#define wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER      0x00000002
#define wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER      0x00000004
#define wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER        0x00000008
#define wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER        0x00000010
#define wxTEXT_ATTR_BULLET_STYLE_SYMBOL             0x00000020
#define wxTEXT_ATTR_BULLET_STYLE_BITMAP             0x00000040
#define wxTEXT_ATTR_BULLET_STYLE_PARENTHESES        0x00000080
#define wxTEXT_ATTR_BULLET_STYLE_PERIOD             0x00000100
#define wxTEXT_ATTR_BULLET_STYLE_STANDARD           0x00000200
#define wxTEXT_ATTR_BULLET_STYLE_RIGHT_PARENTHESIS  0x00000400
#define wxTEXT_ATTR_BULLET_STYLE_OUTLINE            0x00000800

#define wxTEXT_ATTR_BULLET_STYLE_ALIGN_LEFT         0x00000000
#define wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT        0x00001000
#define wxTEXT_ATTR_BULLET_STYLE_ALIGN_CENTRE       0x00002000
#define wxTEXT_ATTR_EFFECT_NONE                     0x00000000
#define wxTEXT_ATTR_EFFECT_CAPITALS                 0x00000001
#define wxTEXT_ATTR_EFFECT_SMALL_CAPITALS           0x00000002
#define wxTEXT_ATTR_EFFECT_STRIKETHROUGH            0x00000004
#define wxTEXT_ATTR_EFFECT_DOUBLE_STRIKETHROUGH     0x00000008
#define wxTEXT_ATTR_EFFECT_SHADOW                   0x00000010
#define wxTEXT_ATTR_EFFECT_EMBOSS                   0x00000020
#define wxTEXT_ATTR_EFFECT_OUTLINE                  0x00000040
#define wxTEXT_ATTR_EFFECT_ENGRAVE                  0x00000080
#define wxTEXT_ATTR_EFFECT_SUPERSCRIPT              0x00000100
#define wxTEXT_ATTR_EFFECT_SUBSCRIPT                0x00000200
#define wxTEXT_ATTR_LINE_SPACING_NORMAL         10
#define wxTEXT_ATTR_LINE_SPACING_HALF           15
#define wxTEXT_ATTR_LINE_SPACING_TWICE          20

#define wxTEXT_ATTR_CHARACTER (wxTEXT_ATTR_FONT|wxTEXT_ATTR_EFFECTS|wxTEXT_ATTR_BACKGROUND_COLOUR|   \
                               wxTEXT_ATTR_TEXT_COLOUR|wxTEXT_ATTR_CHARACTER_STYLE_NAME|wxTEXT_ATTR_URL)

#define wxTEXT_ATTR_PARAGRAPH (wxTEXT_ATTR_ALIGNMENT|wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_TABS|\
                               wxTEXT_ATTR_PARA_SPACING_BEFORE|wxTEXT_ATTR_PARA_SPACING_AFTER|wxTEXT_ATTR_LINE_SPACING|\
                               wxTEXT_ATTR_BULLET_STYLE|wxTEXT_ATTR_BULLET_NUMBER|wxTEXT_ATTR_BULLET_TEXT|wxTEXT_ATTR_BULLET_NAME|\
                               wxTEXT_ATTR_PARAGRAPH_STYLE_NAME|wxTEXT_ATTR_LIST_STYLE_NAME|wxTEXT_ATTR_OUTLINE_LEVEL|wxTEXT_ATTR_PAGE_BREAK)

#define wxTEXT_ATTR_ALL (wxTEXT_ATTR_CHARACTER|wxTEXT_ATTR_PARAGRAPH)

#define wxSCRIPT_MUL_FACTOR             1.5

class wxRichTextRange {
  public:
    wxRichTextRange() { m_start = 0; m_end = 0; }
    wxRichTextRange( long start, long end ) { m_start = start; m_end = end; }
    wxRichTextRange( const wxRichTextRange& range ) { m_start = range.m_start; m_end = range.m_end; }
    ~wxRichTextRange() {}

    void operator =( const wxRichTextRange& range ) { m_start = range.m_start; m_end = range.m_end; }
    bool operator ==( const wxRichTextRange& range ) const { return ( m_start == range.m_start && m_end == range.m_end ); }
    bool operator !=( const wxRichTextRange& range ) const { return ( m_start != range.m_start || m_end != range.m_end ); }
    wxRichTextRange operator -( const wxRichTextRange& range ) const {
      return wxRichTextRange( m_start - range.m_start, m_end - range.m_end );
    }
    wxRichTextRange operator +( const wxRichTextRange& range ) const {
      return wxRichTextRange( m_start + range.m_start, m_end + range.m_end );
    }

    void SetRange( long start, long end ) { m_start = start; m_end = end; }

    void SetStart( long start ) { m_start = start; }
    long GetStart() const { return m_start; }

    void SetEnd( long end ) { m_end = end; }
    long GetEnd() const { return m_end; }
    bool IsOutside( const wxRichTextRange& range ) const { return range.m_start > m_end || range.m_end < m_start; }
    bool IsWithin( const wxRichTextRange& range ) const { return m_start >= range.m_start && m_end <= range.m_end; }
    bool Contains( long pos ) const { return pos >= m_start && pos <= m_end ; }
    bool LimitTo( const wxRichTextRange& range ) ;
    long GetLength() const { return m_end - m_start + 1; }
    void Swap() { long tmp = m_start; m_start = m_end; m_end = tmp; }
    wxRichTextRange ToInternal() const { return wxRichTextRange( m_start, m_end - 1 ); }
    wxRichTextRange FromInternal() const { return wxRichTextRange( m_start, m_end + 1 ); }

  protected:
    long m_start;
    long m_end;
};

#define wxRICHTEXT_ALL  wxRichTextRange(-2, -2)
#define wxRICHTEXT_NONE  wxRichTextRange(-1, -1)

class wxTextAttrEx: public wxTextAttr {
  public:

    wxTextAttrEx( const wxTextAttrEx& attr );
    wxTextAttrEx( const wxTextAttr& attr ) { Init(); ( *this ) = attr; }
    wxTextAttrEx() { Init(); }    void Init();
    void Copy( const wxTextAttrEx& attr );
    void operator= ( const wxTextAttrEx& attr );
    void operator= ( const wxTextAttr& attr );
    bool operator== ( const wxTextAttrEx& attr ) const;
    void SetCharacterStyleName( const wxString& name ) {
      m_characterStyleName = name;
      SetFlags( GetFlags() | wxTEXT_ATTR_CHARACTER_STYLE_NAME );
    }
    void SetParagraphStyleName( const wxString& name ) {
      m_paragraphStyleName = name;
      SetFlags( GetFlags() | wxTEXT_ATTR_PARAGRAPH_STYLE_NAME );
    }
    void SetListStyleName( const wxString& name ) {
      m_listStyleName = name;
      SetFlags( GetFlags() | wxTEXT_ATTR_LIST_STYLE_NAME );
    }
    void SetParagraphSpacingAfter( int spacing ) {
      m_paragraphSpacingAfter = spacing;
      SetFlags( GetFlags() | wxTEXT_ATTR_PARA_SPACING_AFTER );
    }
    void SetParagraphSpacingBefore( int spacing ) {
      m_paragraphSpacingBefore = spacing;
      SetFlags( GetFlags() | wxTEXT_ATTR_PARA_SPACING_BEFORE );
    }
    void SetLineSpacing( int spacing ) { m_lineSpacing = spacing; SetFlags( GetFlags() | wxTEXT_ATTR_LINE_SPACING ); }
    void SetBulletStyle( int style ) { m_bulletStyle = style; SetFlags( GetFlags() | wxTEXT_ATTR_BULLET_STYLE ); }
    void SetBulletNumber( int n ) { m_bulletNumber = n; SetFlags( GetFlags() | wxTEXT_ATTR_BULLET_NUMBER ); }
    void SetBulletText( const wxString& text ) { m_bulletText = text; SetFlags( GetFlags() | wxTEXT_ATTR_BULLET_TEXT ); }
    void SetBulletName( const wxString& name ) { m_bulletName = name; SetFlags( GetFlags() | wxTEXT_ATTR_BULLET_NAME ); }
    void SetBulletFont( const wxString& bulletFont ) { m_bulletFont = bulletFont; }
    void SetURL( const wxString& url ) { m_urlTarget = url; SetFlags( GetFlags() | wxTEXT_ATTR_URL ); }
    void SetPageBreak( bool pageBreak = true ) {
      SetFlags( pageBreak ? ( GetFlags() | wxTEXT_ATTR_PAGE_BREAK ) : ( GetFlags() & ~wxTEXT_ATTR_PAGE_BREAK ) );
    }
    void SetTextEffects( int effects ) { m_textEffects = effects; SetFlags( GetFlags() | wxTEXT_ATTR_EFFECTS ); }
    void SetTextEffectFlags( int effects ) { m_textEffectFlags = effects; }
    void SetOutlineLevel( int level ) { m_outlineLevel = level; SetFlags( GetFlags() | wxTEXT_ATTR_OUTLINE_LEVEL ); }

    const wxString& GetCharacterStyleName() const { return m_characterStyleName; }
    const wxString& GetParagraphStyleName() const { return m_paragraphStyleName; }
    const wxString& GetListStyleName() const { return m_listStyleName; }
    int GetParagraphSpacingAfter() const { return m_paragraphSpacingAfter; }
    int GetParagraphSpacingBefore() const { return m_paragraphSpacingBefore; }
    int GetLineSpacing() const { return m_lineSpacing; }
    int GetBulletStyle() const { return m_bulletStyle; }
    int GetBulletNumber() const { return m_bulletNumber; }
    const wxString& GetBulletText() const { return m_bulletText; }
    const wxString& GetBulletName() const { return m_bulletName; }
    const wxString& GetBulletFont() const { return m_bulletFont; }
    const wxString& GetURL() const { return m_urlTarget; }
    int GetTextEffects() const { return m_textEffects; }
    int GetTextEffectFlags() const { return m_textEffectFlags; }
    int GetOutlineLevel() const { return m_outlineLevel; }

    bool HasFontWeight() const { return ( GetFlags() & wxTEXT_ATTR_FONT_WEIGHT ) != 0; }
    bool HasFontSize() const { return ( GetFlags() & wxTEXT_ATTR_FONT_SIZE ) != 0; }
    bool HasFontItalic() const { return ( GetFlags() & wxTEXT_ATTR_FONT_ITALIC ) != 0; }
    bool HasFontUnderlined() const { return ( GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE ) != 0; }
    bool HasFontFaceName() const { return ( GetFlags() & wxTEXT_ATTR_FONT_FACE ) != 0; }

    bool HasParagraphSpacingAfter() const { return HasFlag( wxTEXT_ATTR_PARA_SPACING_AFTER ); }
    bool HasParagraphSpacingBefore() const { return HasFlag( wxTEXT_ATTR_PARA_SPACING_BEFORE ); }
    bool HasLineSpacing() const { return HasFlag( wxTEXT_ATTR_LINE_SPACING ); }
    bool HasCharacterStyleName() const {
      return HasFlag( wxTEXT_ATTR_CHARACTER_STYLE_NAME ) && !m_characterStyleName.IsEmpty();
    }
    bool HasParagraphStyleName() const {
      return HasFlag( wxTEXT_ATTR_PARAGRAPH_STYLE_NAME ) && !m_paragraphStyleName.IsEmpty();
    }
    bool HasListStyleName() const { return HasFlag( wxTEXT_ATTR_LIST_STYLE_NAME ) || !m_listStyleName.IsEmpty(); }
    bool HasBulletStyle() const { return HasFlag( wxTEXT_ATTR_BULLET_STYLE ); }
    bool HasBulletNumber() const { return HasFlag( wxTEXT_ATTR_BULLET_NUMBER ); }
    bool HasBulletText() const { return HasFlag( wxTEXT_ATTR_BULLET_TEXT ); }
    bool HasBulletName() const { return HasFlag( wxTEXT_ATTR_BULLET_NAME ); }
    bool HasURL() const { return HasFlag( wxTEXT_ATTR_URL ); }
    bool HasPageBreak() const { return HasFlag( wxTEXT_ATTR_PAGE_BREAK ); }
    bool HasTextEffects() const { return HasFlag( wxTEXT_ATTR_EFFECTS ); }
    bool HasTextEffect( int effect ) const {
      return HasFlag( wxTEXT_ATTR_EFFECTS ) && ( ( GetTextEffectFlags() & effect ) != 0 );
    }
    bool HasOutlineLevel() const { return HasFlag( wxTEXT_ATTR_OUTLINE_LEVEL ); }
    bool IsCharacterStyle() const { return ( 0 != ( GetFlags() & wxTEXT_ATTR_CHARACTER ) ); }
    bool IsParagraphStyle() const { return ( 0 != ( GetFlags() & wxTEXT_ATTR_PARAGRAPH ) ); }
    bool IsDefault() const {
      return ( GetFlags() == 0 );
    }

    static wxTextAttrEx CombineEx( const wxTextAttrEx& attr, const wxTextAttrEx& attrDef, const wxTextCtrlBase *text );

  private:

    int                 m_paragraphSpacingAfter;
    int                 m_paragraphSpacingBefore;
    int                 m_lineSpacing;
    int                 m_bulletStyle;
    int                 m_bulletNumber;
    int                 m_textEffects;
    int                 m_textEffectFlags;
    int                 m_outlineLevel;
    wxString            m_bulletText;
    wxString            m_bulletFont;
    wxString            m_bulletName;
    wxString            m_urlTarget;
    wxString            m_characterStyleName;
    wxString            m_paragraphStyleName;
    wxString            m_listStyleName;
};

class wxRichTextAttr {
  public:

    wxRichTextAttr( const wxTextAttrEx& attr );
    wxRichTextAttr( const wxRichTextAttr& attr );
    wxRichTextAttr() { Init(); }
    wxRichTextAttr( const wxColour& colText, const wxColour& colBack = wxNullColour,
                    wxTextAttrAlignment alignment = wxTEXT_ALIGNMENT_DEFAULT );
    void Init();
    void Copy( const wxRichTextAttr& attr );
    void operator= ( const wxRichTextAttr& attr );
    void operator= ( const wxTextAttrEx& attr );
    bool operator== ( const wxRichTextAttr& attr ) const;
    operator wxTextAttrEx() const ;
    wxFont CreateFont() const;
    bool GetFontAttributes( const wxFont& font );
    void SetTextColour( const wxColour& colText ) { m_colText = colText; m_flags |= wxTEXT_ATTR_TEXT_COLOUR; }
    void SetBackgroundColour( const wxColour& colBack ) { m_colBack = colBack; m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR; }
    void SetAlignment( wxTextAttrAlignment alignment ) { m_textAlignment = alignment; m_flags |= wxTEXT_ATTR_ALIGNMENT; }
    void SetTabs( const wxArrayInt& tabs ) { m_tabs = tabs; m_flags |= wxTEXT_ATTR_TABS; }
    void SetLeftIndent( int indent, int subIndent = 0 ) {
      m_leftIndent = indent;
      m_leftSubIndent = subIndent;
      m_flags |= wxTEXT_ATTR_LEFT_INDENT;
    }
    void SetRightIndent( int indent ) { m_rightIndent = indent; m_flags |= wxTEXT_ATTR_RIGHT_INDENT; }
    void SetFontSize( int pointSize ) { m_fontSize = pointSize; m_flags |= wxTEXT_ATTR_FONT_SIZE; }
    void SetFontStyle( int fontStyle ) { m_fontStyle = fontStyle; m_flags |= wxTEXT_ATTR_FONT_ITALIC; }
    void SetFontWeight( int fontWeight ) { m_fontWeight = fontWeight; m_flags |= wxTEXT_ATTR_FONT_WEIGHT; }
    void SetFontFaceName( const wxString& faceName ) { m_fontFaceName = faceName; m_flags |= wxTEXT_ATTR_FONT_FACE; }
    void SetFontUnderlined( bool underlined ) { m_fontUnderlined = underlined; m_flags |= wxTEXT_ATTR_FONT_UNDERLINE; }
    void SetFlags( long flags ) { m_flags = flags; }
    void SetCharacterStyleName( const wxString& name ) {
      m_characterStyleName = name;
      m_flags |= wxTEXT_ATTR_CHARACTER_STYLE_NAME;
    }
    void SetParagraphStyleName( const wxString& name ) {
      m_paragraphStyleName = name;
      m_flags |= wxTEXT_ATTR_PARAGRAPH_STYLE_NAME;
    }
    void SetListStyleName( const wxString& name ) {
      m_listStyleName = name;
      SetFlags( GetFlags() | wxTEXT_ATTR_LIST_STYLE_NAME );
    }
    void SetParagraphSpacingAfter( int spacing ) {
      m_paragraphSpacingAfter = spacing;
      m_flags |= wxTEXT_ATTR_PARA_SPACING_AFTER;
    }
    void SetParagraphSpacingBefore( int spacing ) {
      m_paragraphSpacingBefore = spacing;
      m_flags |= wxTEXT_ATTR_PARA_SPACING_BEFORE;
    }
    void SetLineSpacing( int spacing ) { m_lineSpacing = spacing; m_flags |= wxTEXT_ATTR_LINE_SPACING; }
    void SetBulletStyle( int style ) { m_bulletStyle = style; m_flags |= wxTEXT_ATTR_BULLET_STYLE; }
    void SetBulletNumber( int n ) { m_bulletNumber = n; m_flags |= wxTEXT_ATTR_BULLET_NUMBER; }
    void SetBulletText( const wxString& text ) { m_bulletText = text; m_flags |= wxTEXT_ATTR_BULLET_TEXT; }
    void SetBulletFont( const wxString& bulletFont ) { m_bulletFont = bulletFont; }
    void SetBulletName( const wxString& name ) { m_bulletName = name; m_flags |= wxTEXT_ATTR_BULLET_NAME; }
    void SetURL( const wxString& url ) { m_urlTarget = url; m_flags |= wxTEXT_ATTR_URL; }
    void SetPageBreak( bool pageBreak = true ) {
      SetFlags( pageBreak ? ( GetFlags() | wxTEXT_ATTR_PAGE_BREAK ) : ( GetFlags() & ~wxTEXT_ATTR_PAGE_BREAK ) );
    }
    void SetTextEffects( int effects ) { m_textEffects = effects; SetFlags( GetFlags() | wxTEXT_ATTR_EFFECTS ); }
    void SetTextEffectFlags( int effects ) { m_textEffectFlags = effects; }
    void SetOutlineLevel( int level ) { m_outlineLevel = level; SetFlags( GetFlags() | wxTEXT_ATTR_OUTLINE_LEVEL ); }
    const wxColour& GetTextColour() const { return m_colText; }
    const wxColour& GetBackgroundColour() const { return m_colBack; }
    wxTextAttrAlignment GetAlignment() const { return m_textAlignment; }
    const wxArrayInt& GetTabs() const { return m_tabs; }
    long GetLeftIndent() const { return m_leftIndent; }
    long GetLeftSubIndent() const { return m_leftSubIndent; }
    long GetRightIndent() const { return m_rightIndent; }
    long GetFlags() const { return m_flags; }
    int GetFontSize() const { return m_fontSize; }
    int GetFontStyle() const { return m_fontStyle; }
    int GetFontWeight() const { return m_fontWeight; }
    bool GetFontUnderlined() const { return m_fontUnderlined; }
    const wxString& GetFontFaceName() const { return m_fontFaceName; }
    const wxString& GetCharacterStyleName() const { return m_characterStyleName; }
    const wxString& GetParagraphStyleName() const { return m_paragraphStyleName; }
    const wxString& GetListStyleName() const { return m_listStyleName; }
    int GetParagraphSpacingAfter() const { return m_paragraphSpacingAfter; }
    int GetParagraphSpacingBefore() const { return m_paragraphSpacingBefore; }
    int GetLineSpacing() const { return m_lineSpacing; }
    int GetBulletStyle() const { return m_bulletStyle; }
    int GetBulletNumber() const { return m_bulletNumber; }
    const wxString& GetBulletText() const { return m_bulletText; }
    const wxString& GetBulletFont() const { return m_bulletFont; }
    const wxString& GetBulletName() const { return m_bulletName; }
    const wxString& GetURL() const { return m_urlTarget; }
    int GetTextEffects() const { return m_textEffects; }
    int GetTextEffectFlags() const { return m_textEffectFlags; }
    int GetOutlineLevel() const { return m_outlineLevel; }

    bool HasTextColour() const { return m_colText.Ok() && HasFlag( wxTEXT_ATTR_TEXT_COLOUR ) ; }
    bool HasBackgroundColour() const { return m_colBack.Ok() && HasFlag( wxTEXT_ATTR_BACKGROUND_COLOUR ) ; }
    bool HasAlignment() const {
      return ( m_textAlignment != wxTEXT_ALIGNMENT_DEFAULT ) && ( ( m_flags & wxTEXT_ATTR_ALIGNMENT ) != 0 ) ;
    }
    bool HasTabs() const { return ( m_flags & wxTEXT_ATTR_TABS ) != 0 ; }
    bool HasLeftIndent() const { return ( m_flags & wxTEXT_ATTR_LEFT_INDENT ) != 0 ; }
    bool HasRightIndent() const { return ( m_flags & wxTEXT_ATTR_RIGHT_INDENT ) != 0 ; }
    bool HasFontWeight() const { return ( m_flags & wxTEXT_ATTR_FONT_WEIGHT ) != 0; }
    bool HasFontSize() const { return ( m_flags & wxTEXT_ATTR_FONT_SIZE ) != 0; }
    bool HasFontItalic() const { return ( m_flags & wxTEXT_ATTR_FONT_ITALIC ) != 0; }
    bool HasFontUnderlined() const { return ( m_flags & wxTEXT_ATTR_FONT_UNDERLINE ) != 0; }
    bool HasFontFaceName() const { return ( m_flags & wxTEXT_ATTR_FONT_FACE ) != 0; }
    bool HasFont() const { return ( m_flags & ( wxTEXT_ATTR_FONT ) ) != 0; }

    bool HasParagraphSpacingAfter() const { return ( m_flags & wxTEXT_ATTR_PARA_SPACING_AFTER ) != 0; }
    bool HasParagraphSpacingBefore() const { return ( m_flags & wxTEXT_ATTR_PARA_SPACING_BEFORE ) != 0; }
    bool HasLineSpacing() const { return ( m_flags & wxTEXT_ATTR_LINE_SPACING ) != 0; }
    bool HasCharacterStyleName() const {
      return ( m_flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME ) != 0 && !m_characterStyleName.IsEmpty();
    }
    bool HasParagraphStyleName() const {
      return ( m_flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME ) != 0 && !m_paragraphStyleName.IsEmpty();
    }
    bool HasListStyleName() const { return HasFlag( wxTEXT_ATTR_LIST_STYLE_NAME ) || !m_listStyleName.IsEmpty(); }
    bool HasBulletStyle() const { return ( m_flags & wxTEXT_ATTR_BULLET_STYLE ) != 0; }
    bool HasBulletNumber() const { return ( m_flags & wxTEXT_ATTR_BULLET_NUMBER ) != 0; }
    bool HasBulletText() const { return ( m_flags & wxTEXT_ATTR_BULLET_TEXT ) != 0; }
    bool HasBulletName() const { return ( m_flags & wxTEXT_ATTR_BULLET_NAME ) != 0; }
    bool HasURL() const { return HasFlag( wxTEXT_ATTR_URL ); }
    bool HasPageBreak() const { return HasFlag( wxTEXT_ATTR_PAGE_BREAK ); }
    bool HasTextEffects() const { return HasFlag( wxTEXT_ATTR_EFFECTS ); }
    bool HasTextEffect( int effect ) const {
      return HasFlag( wxTEXT_ATTR_EFFECTS ) && ( ( GetTextEffectFlags() & effect ) != 0 );
    }
    bool HasOutlineLevel() const { return HasFlag( wxTEXT_ATTR_OUTLINE_LEVEL ); }

    bool HasFlag( long flag ) const { return ( m_flags & flag ) != 0; }
    bool IsCharacterStyle() const { return ( 0 != ( GetFlags() & wxTEXT_ATTR_CHARACTER ) ); }
    bool IsParagraphStyle() const { return ( 0 != ( GetFlags() & wxTEXT_ATTR_PARAGRAPH ) ); }
    bool IsDefault() const {
      return GetFlags() == 0;
    }

    bool Apply( const wxRichTextAttr& style, const wxRichTextAttr* compareWith = NULL );

    wxRichTextAttr Combine( const wxRichTextAttr& style, const wxRichTextAttr* compareWith = NULL ) const;

  private:
    long                m_flags;
    wxArrayInt          m_tabs;
    int                 m_leftIndent;
    int                 m_leftSubIndent;
    int                 m_rightIndent;
    wxTextAttrAlignment m_textAlignment;

    int                 m_paragraphSpacingAfter;
    int                 m_paragraphSpacingBefore;
    int                 m_lineSpacing;
    int                 m_bulletStyle;
    int                 m_bulletNumber;
    int                 m_textEffects;
    int                 m_textEffectFlags;
    int                 m_outlineLevel;
    wxString            m_bulletText;
    wxString            m_bulletFont;
    wxString            m_bulletName;
    wxString            m_urlTarget;
    wxColour            m_colText,
                        m_colBack;
    int                 m_fontSize;
    int                 m_fontStyle;
    int                 m_fontWeight;
    bool                m_fontUnderlined;
    wxString            m_fontFaceName;
    wxString            m_characterStyleName;
    wxString            m_paragraphStyleName;
    wxString            m_listStyleName;
};

class  wxRichTextObject: public wxObject {
    DECLARE_CLASS( wxRichTextObject )
  public:
    wxRichTextObject( wxRichTextObject* parent = NULL );
    virtual ~wxRichTextObject();
    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style ) = 0;
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style ) = 0;
    virtual int HitTest( wxDC & ( dc ), const wxPoint & ( pt ), long & ( textPosition ) ) { return false; }
    virtual bool FindPosition( wxDC & ( dc ), long ( index ), wxPoint & ( pt ), int* ( height ), bool ( forceLineStart ) ) {
      return false;
    }
    virtual wxSize GetBestSize() const { return m_size; }
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags,
                               wxPoint position = wxPoint( 0, 0 ) ) const  = 0;
    virtual wxRichTextObject* DoSplit( long ( pos ) ) { return NULL; }
    virtual void CalculateRange( long start, long& end ) { end = start ; m_range.SetRange( start, end ); }
    virtual bool DeleteRange( const wxRichTextRange & ( range ) ) { return false; }
    virtual bool IsEmpty() const { return false; }
    virtual wxString GetTextForRange( const wxRichTextRange & ( range ) ) const { return wxEmptyString; }
    virtual bool CanMerge( wxRichTextObject * ( object ) ) const { return false; }
    virtual bool Merge( wxRichTextObject * ( object ) ) { return false; }
    virtual void Dump( wxTextOutputStream& stream );
    virtual wxSize GetCachedSize() const { return m_size; }
    virtual void SetCachedSize( const wxSize& sz ) { m_size = sz; }
    virtual wxPoint GetPosition() const { return m_pos; }
    virtual void SetPosition( const wxPoint& pos ) { m_pos = pos; }
    virtual wxRect GetRect() const { return wxRect( GetPosition(), GetCachedSize() ); }
    void SetRange( const wxRichTextRange& range ) { m_range = range; }
    const wxRichTextRange& GetRange() const { return m_range; }
    wxRichTextRange& GetRange() { return m_range; }
    virtual bool GetDirty() const { return m_dirty; }
    virtual void SetDirty( bool dirty ) { m_dirty = dirty; }
    virtual bool IsComposite() const { return false; }
    virtual wxRichTextObject* GetParent() const { return m_parent; }
    virtual void SetParent( wxRichTextObject* parent ) { m_parent = parent; }
    virtual void SetMargins( int margin );
    virtual void SetMargins( int leftMargin, int rightMargin, int topMargin, int bottomMargin );
    virtual int GetLeftMargin() const { return m_leftMargin; }
    virtual int GetRightMargin() const { return m_rightMargin; }
    virtual int GetTopMargin() const { return m_topMargin; }
    virtual int GetBottomMargin() const { return m_bottomMargin; }
    void SetAttributes( const wxTextAttrEx& attr ) { m_attributes = attr; }
    const wxTextAttrEx& GetAttributes() const { return m_attributes; }
    wxTextAttrEx& GetAttributes() { return m_attributes; }
    void SetDescent( int descent ) { m_descent = descent; }
    int GetDescent() const { return m_descent; }
    wxRichTextBuffer* GetBuffer() const;
    virtual wxRichTextObject* Clone() const { return NULL; }
    void Copy( const wxRichTextObject& obj );
    void Reference() { m_refCount ++; }
    void Dereference();
    int ConvertTenthsMMToPixels( wxDC& dc, int units );
    static int ConvertTenthsMMToPixels( int ppi, int units );

  protected:
    wxSize                  m_size;
    wxPoint                 m_pos;
    int                     m_descent;
    bool                    m_dirty;
    int                     m_refCount;
    wxRichTextObject*       m_parent;
    wxRichTextRange         m_range;
    int                     m_leftMargin;
    int                     m_rightMargin;
    int                     m_topMargin;
    int                     m_bottomMargin;
    wxTextAttrEx            m_attributes;
};

WX_DECLARE_LIST_WITH_DECL( wxRichTextObject, wxRichTextObjectList );

class wxRichTextCompositeObject: public wxRichTextObject {
    DECLARE_CLASS( wxRichTextCompositeObject )
  public:
    wxRichTextCompositeObject( wxRichTextObject* parent = NULL );
    virtual ~wxRichTextCompositeObject();
    virtual int HitTest( wxDC& dc, const wxPoint& pt, long& textPosition );
    virtual bool FindPosition( wxDC& dc, long index, wxPoint& pt, int* height, bool forceLineStart );
    virtual void CalculateRange( long start, long& end );
    virtual bool DeleteRange( const wxRichTextRange& range );
    virtual wxString GetTextForRange( const wxRichTextRange& range ) const;
    virtual void Dump( wxTextOutputStream& stream );
    wxRichTextObjectList& GetChildren() { return m_children; }
    const wxRichTextObjectList& GetChildren() const { return m_children; }
    size_t GetChildCount() const ;
    wxRichTextObject* GetChild( size_t n ) const ;
    virtual bool GetDirty() const { return m_dirty; }
    virtual void SetDirty( bool dirty ) { m_dirty = dirty; }
    virtual bool IsComposite() const { return true; }
    virtual bool IsEmpty() const { return GetChildCount() == 0; }

    void Copy( const wxRichTextCompositeObject& obj );
    void operator= ( const wxRichTextCompositeObject& obj ) { Copy( obj ); }
    size_t AppendChild( wxRichTextObject* child ) ;
    bool InsertChild( wxRichTextObject* child, wxRichTextObject* inFrontOf ) ;
    bool RemoveChild( wxRichTextObject* child, bool deleteChild = false ) ;
    bool DeleteChildren() ;
    bool Defragment();

  protected:
    wxRichTextObjectList    m_children;
};

class wxRichTextBox: public wxRichTextCompositeObject {
    DECLARE_DYNAMIC_CLASS( wxRichTextBox )
  public:
    wxRichTextBox( wxRichTextObject* parent = NULL );
    wxRichTextBox( const wxRichTextBox& obj ): wxRichTextCompositeObject() { Copy( obj ); }

    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style );
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style );
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags,
                               wxPoint position = wxPoint( 0, 0 ) ) const;
    virtual wxRichTextObject* Clone() const { return new wxRichTextBox( *this ); }
    void Copy( const wxRichTextBox& obj );

  protected:
};

class wxRichTextParagraphLayoutBox: public wxRichTextBox {
    DECLARE_DYNAMIC_CLASS( wxRichTextParagraphLayoutBox )
  public:
    wxRichTextParagraphLayoutBox( wxRichTextObject* parent = NULL );
    wxRichTextParagraphLayoutBox( const wxRichTextParagraphLayoutBox& obj ): wxRichTextBox() { Init(); Copy( obj ); }

    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style );
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style );
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags,
                               wxPoint position = wxPoint( 0, 0 ) ) const;
    virtual bool DeleteRange( const wxRichTextRange& range );
    virtual wxString GetTextForRange( const wxRichTextRange& range ) const;
    void SetRichTextCtrl( wxRichTextCtrl* ctrl ) { m_ctrl = ctrl; }
    wxRichTextCtrl* GetRichTextCtrl() const { return m_ctrl; }
    void SetPartialParagraph( bool partialPara ) { m_partialParagraph = partialPara; }
    bool GetPartialParagraph() const { return m_partialParagraph; }
    virtual wxRichTextStyleSheet* GetStyleSheet() const { return NULL; }
    void Init();
    virtual void Clear();
    virtual void Reset();
    virtual wxRichTextRange AddParagraph( const wxString& text, wxTextAttrEx* paraStyle = NULL );
    virtual wxRichTextRange AddImage( const wxImage& image, wxTextAttrEx* paraStyle = NULL );
    virtual wxRichTextRange AddParagraphs( const wxString& text, wxTextAttrEx* paraStyle = NULL );
    virtual wxRichTextLine* GetLineAtPosition( long pos, bool caretPosition = false ) const;
    virtual wxRichTextLine* GetLineAtYPosition( int y ) const;
    virtual wxRichTextParagraph* GetParagraphAtPosition( long pos, bool caretPosition = false ) const;
    virtual wxSize GetLineSizeAtPosition( long pos, bool caretPosition = false ) const;
    virtual long GetVisibleLineNumber( long pos, bool caretPosition = false, bool startOfLine = false ) const;
    virtual wxRichTextLine* GetLineForVisibleLineNumber( long lineNumber ) const;
    virtual wxRichTextObject* GetLeafObjectAtPosition( long position ) const;
    virtual wxRichTextParagraph* GetParagraphAtLine( long paragraphNumber ) const;
    virtual wxRichTextParagraph* GetParagraphForLine( wxRichTextLine* line ) const;
    virtual int GetParagraphLength( long paragraphNumber ) const;
    virtual int GetParagraphCount() const { return wx_static_cast( int, GetChildCount() ); }
    virtual int GetLineCount() const;
    virtual wxString GetParagraphText( long paragraphNumber ) const;
    virtual long XYToPosition( long x, long y ) const;
    virtual bool PositionToXY( long pos, long* x, long* y ) const;
    virtual bool SetStyle( const wxRichTextRange& range, const wxRichTextAttr& style, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO );
    virtual bool SetStyle( const wxRichTextRange& range, const wxTextAttrEx& style, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO );
    virtual bool GetStyle( long position, wxTextAttrEx& style );
    virtual bool GetStyle( long position, wxRichTextAttr& style );
    virtual bool GetUncombinedStyle( long position, wxTextAttrEx& style );
    virtual bool GetUncombinedStyle( long position, wxRichTextAttr& style );
    virtual bool DoGetStyle( long position, wxTextAttrEx& style, bool combineStyles = true );
    virtual bool GetStyleForRange( const wxRichTextRange& range, wxTextAttrEx& style );
    bool CollectStyle( wxTextAttrEx& currentStyle, const wxTextAttrEx& style, long& multipleStyleAttributes,
                       int& multipleTextEffectAttributes );
    virtual bool SetListStyle( const wxRichTextRange& range, wxRichTextListStyleDefinition* def,
                               int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1 );
    virtual bool SetListStyle( const wxRichTextRange& range, const wxString& defName,
                               int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1 );
    virtual bool ClearListStyle( const wxRichTextRange& range, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO );
    virtual bool NumberList( const wxRichTextRange& range, wxRichTextListStyleDefinition* def = NULL,
                             int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1 );
    virtual bool NumberList( const wxRichTextRange& range, const wxString& defName,
                             int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1 );
    virtual bool PromoteList( int promoteBy, const wxRichTextRange& range, wxRichTextListStyleDefinition* def = NULL,
                              int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int specifiedLevel = -1 );
    virtual bool PromoteList( int promoteBy, const wxRichTextRange& range, const wxString& defName,
                              int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int specifiedLevel = -1 );
    virtual bool DoNumberList( const wxRichTextRange& range, const wxRichTextRange& promotionRange, int promoteBy,
                               wxRichTextListStyleDefinition* def, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO,
                               int startFrom = 1, int specifiedLevel = -1 );
    virtual bool FindNextParagraphNumber( wxRichTextParagraph* previousParagraph, wxRichTextAttr& attr ) const;
    virtual bool HasCharacterAttributes( const wxRichTextRange& range, const wxTextAttrEx& style ) const;
    virtual bool HasCharacterAttributes( const wxRichTextRange& range, const wxRichTextAttr& style ) const;
    virtual bool HasParagraphAttributes( const wxRichTextRange& range, const wxTextAttrEx& style ) const;
    virtual bool HasParagraphAttributes( const wxRichTextRange& range, const wxRichTextAttr& style ) const;
    virtual wxRichTextObject* Clone() const { return new wxRichTextParagraphLayoutBox( *this ); }
    virtual bool InsertFragment( long position, wxRichTextParagraphLayoutBox& fragment );
    virtual bool CopyFragment( const wxRichTextRange& range, wxRichTextParagraphLayoutBox& fragment );
    virtual bool ApplyStyleSheet( wxRichTextStyleSheet* styleSheet );
    void Copy( const wxRichTextParagraphLayoutBox& obj );
    void operator= ( const wxRichTextParagraphLayoutBox& obj ) { Copy( obj ); }
    virtual void UpdateRanges() { long end; CalculateRange( 0, end ); }
    virtual wxString GetText() const;
    virtual bool SetDefaultStyle( const wxTextAttrEx& style );
    virtual const wxTextAttrEx& GetDefaultStyle() const { return m_defaultAttributes; }
    virtual void SetBasicStyle( const wxTextAttrEx& style ) { m_attributes = style; }
    virtual void SetBasicStyle( const wxRichTextAttr& style ) { m_attributes = style; }
    virtual const wxTextAttrEx& GetBasicStyle() const { return m_attributes; }
    void Invalidate( const wxRichTextRange& invalidRange = wxRICHTEXT_ALL );
    wxRichTextRange GetInvalidRange( bool wholeParagraphs = false ) const;

  protected:
    wxRichTextCtrl* m_ctrl;
    wxTextAttrEx    m_defaultAttributes;
    wxRichTextRange m_invalidRange;
    bool            m_partialParagraph;
};

class wxRichTextLine {
  public:
    wxRichTextLine( wxRichTextParagraph* parent );
    wxRichTextLine( const wxRichTextLine& obj ) { Init( NULL ); Copy( obj ); }
    virtual ~wxRichTextLine() {}
    void SetRange( const wxRichTextRange& range ) { m_range = range; }
    void SetRange( long from, long to ) { m_range = wxRichTextRange( from, to ); }
    wxRichTextParagraph* GetParent() { return m_parent; }
    const wxRichTextRange& GetRange() const { return m_range; }
    wxRichTextRange& GetRange() { return m_range; }    wxRichTextRange GetAbsoluteRange() const;
    virtual wxSize GetSize() const { return m_size; }
    virtual void SetSize( const wxSize& sz ) { m_size = sz; }
    virtual wxPoint GetPosition() const { return m_pos; }
    virtual void SetPosition( const wxPoint& pos ) { m_pos = pos; }
    virtual wxPoint GetAbsolutePosition() const;
    virtual wxRect GetRect() const { return wxRect( GetAbsolutePosition(), GetSize() ); }
    void SetDescent( int descent ) { m_descent = descent; }
    int GetDescent() const { return m_descent; }

    #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
    wxArrayInt& GetObjectSizes() { return m_objectSizes; }
    const wxArrayInt& GetObjectSizes() const { return m_objectSizes; }
    #endif

    void Init( wxRichTextParagraph* parent );
    void Copy( const wxRichTextLine& obj );
    virtual wxRichTextLine* Clone() const { return new wxRichTextLine( *this ); }

  protected:
    wxRichTextRange     m_range;
    wxPoint             m_pos;
    wxSize              m_size;
    int                 m_descent;
    wxRichTextParagraph* m_parent;
    #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
    wxArrayInt          m_objectSizes;
    #endif
};

WX_DECLARE_LIST_WITH_DECL( wxRichTextLine, wxRichTextLineList );

class wxRichTextParagraph: public wxRichTextBox {
    DECLARE_DYNAMIC_CLASS( wxRichTextParagraph )
  public:
    wxRichTextParagraph( wxRichTextObject* parent = NULL, wxTextAttrEx* style = NULL );
    wxRichTextParagraph( const wxString& text, wxRichTextObject* parent = NULL, wxTextAttrEx* paraStyle = NULL,
                         wxTextAttrEx* charStyle = NULL );
    virtual ~wxRichTextParagraph();
    wxRichTextParagraph( const wxRichTextParagraph& obj ): wxRichTextBox() { Copy( obj ); }

    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style );
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style );
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags,
                               wxPoint position = wxPoint( 0, 0 ) ) const;
    virtual bool FindPosition( wxDC& dc, long index, wxPoint& pt, int* height, bool forceLineStart );
    virtual int HitTest( wxDC& dc, const wxPoint& pt, long& textPosition );
    virtual void CalculateRange( long start, long& end );

    wxRichTextLineList& GetLines() { return m_cachedLines; }

    void Copy( const wxRichTextParagraph& obj );
    virtual wxRichTextObject* Clone() const { return new wxRichTextParagraph( *this ); }
    void ClearLines();

    virtual void ApplyParagraphStyle( const wxTextAttrEx& attr, const wxRect& rect );
    virtual bool InsertText( long pos, const wxString& text );
    virtual wxRichTextObject* SplitAt( long pos, wxRichTextObject** previousObject = NULL );
    virtual void MoveToList( wxRichTextObject* obj, wxList& list );
    virtual void MoveFromList( wxList& list );
    bool GetContiguousPlainText( wxString& text, const wxRichTextRange& range, bool fromStart = true );
    bool FindWrapPosition( const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition );
    wxRichTextObject* FindObjectAtPosition( long position );
    wxString GetBulletText();
    wxRichTextLine* AllocateLine( int pos );
    bool ClearUnusedLines( int lineCount );
    wxTextAttrEx GetCombinedAttributes( const wxTextAttrEx& contentStyle ) const;
    wxTextAttrEx GetCombinedAttributes() const;
    long GetFirstLineBreakPosition( long pos );
    static void InitDefaultTabs();
    static void ClearDefaultTabs();
    static const wxArrayInt& GetDefaultTabs() { return sm_defaultTabs; }

  protected:

    wxRichTextLineList m_cachedLines;
    static wxArrayInt  sm_defaultTabs;
};

class wxRichTextPlainText: public wxRichTextObject {
    DECLARE_DYNAMIC_CLASS( wxRichTextPlainText )
  public:
    wxRichTextPlainText( const wxString& text = wxEmptyString, wxRichTextObject* parent = NULL, wxTextAttrEx* style = NULL );
    wxRichTextPlainText( const wxRichTextPlainText& obj ): wxRichTextObject() { Copy( obj ); }

    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style );
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style );
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc,
                               int flags, wxPoint position ) const;
    virtual wxString GetTextForRange( const wxRichTextRange& range ) const;
    virtual wxRichTextObject* DoSplit( long pos );
    virtual void CalculateRange( long start, long& end );
    virtual bool DeleteRange( const wxRichTextRange& range );
    virtual bool IsEmpty() const { return m_text.empty(); }
    virtual bool CanMerge( wxRichTextObject* object ) const;
    virtual bool Merge( wxRichTextObject* object );
    virtual void Dump( wxTextOutputStream& stream );
    long GetFirstLineBreakPosition( long pos );

    const wxString& GetText() const { return m_text; }
    void SetText( const wxString& text ) { m_text = text; }

    void Copy( const wxRichTextPlainText& obj );
    virtual wxRichTextObject* Clone() const { return new wxRichTextPlainText( *this ); }
  private:
    bool DrawTabbedString( wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect, wxString& str, wxCoord& x,
                           wxCoord& y, bool selected );

  protected:
    wxString    m_text;
};

class wxDataInputStream;
class wxDataOutputStream;

class wxRichTextImageBlock: public wxObject {
  public:
    wxRichTextImageBlock();
    wxRichTextImageBlock( const wxRichTextImageBlock& block );
    virtual ~wxRichTextImageBlock();
    void Init();
    void Clear();
    virtual bool MakeImageBlock( const wxString& filename, int imageType, wxImage& image, bool convertToJPEG = true );
    virtual bool MakeImageBlock( wxImage& image, int imageType, int quality = 80 );
    bool Write( const wxString& filename );
    bool WriteHex( wxOutputStream& stream );
    bool ReadHex( wxInputStream& stream, int length, int imageType );
    void Copy( const wxRichTextImageBlock& block );
    bool Load( wxImage& image );
    void operator=( const wxRichTextImageBlock& block );
    unsigned char* GetData() const { return m_data; }
    size_t GetDataSize() const { return m_dataSize; }
    int GetImageType() const { return m_imageType; }
    void SetData( unsigned char* image ) { m_data = image; }
    void SetDataSize( size_t size ) { m_dataSize = size; }
    void SetImageType( int imageType ) { m_imageType = imageType; }
    bool Ok() const { return IsOk(); }
    bool IsOk() const { return GetData() != NULL; }
    wxString GetExtension() const;
    static unsigned char* ReadBlock( wxInputStream& stream, size_t size );
    static unsigned char* ReadBlock( const wxString& filename, size_t size );
    static bool WriteBlock( wxOutputStream& stream, unsigned char* block, size_t size );
    static bool WriteBlock( const wxString& filename, unsigned char* block, size_t size );
  protected:
    unsigned char*      m_data;
    size_t              m_dataSize;
    int                 m_imageType;
};

class wxRichTextImage: public wxRichTextObject {
    DECLARE_DYNAMIC_CLASS( wxRichTextImage )
  public:
    wxRichTextImage( wxRichTextObject* parent = NULL ): wxRichTextObject( parent ) { }
    wxRichTextImage( const wxImage& image, wxRichTextObject* parent = NULL, wxTextAttrEx* charStyle = NULL );
    wxRichTextImage( const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent = NULL, wxTextAttrEx* charStyle = NULL );
    wxRichTextImage( const wxRichTextImage& obj ): wxRichTextObject() { Copy( obj ); }

    virtual bool Draw( wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange,
                       const wxRect& rect, int descent, int style );
    virtual bool Layout( wxDC& dc, const wxRect& rect, int style );
    virtual bool GetRangeSize( const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags,
                               wxPoint position = wxPoint( 0, 0 ) ) const;
    virtual bool IsEmpty() const { return !m_image.Ok(); }

    const wxImage& GetImage() const { return m_image; }
    void SetImage( const wxImage& image ) { m_image = image; }
    wxRichTextImageBlock& GetImageBlock() { return m_imageBlock; }

    void Copy( const wxRichTextImage& obj );
    virtual wxRichTextObject* Clone() const { return new wxRichTextImage( *this ); }
    virtual bool LoadFromBlock();
    virtual bool MakeBlock();

  protected:
    wxImage                 m_image;
    wxBitmap                m_bitmap;
    wxRichTextImageBlock    m_imageBlock;
};

class wxRichTextCommand;
class wxRichTextAction;

class wxRichTextBuffer: public wxRichTextParagraphLayoutBox {
    DECLARE_DYNAMIC_CLASS( wxRichTextBuffer )
  public:
    wxRichTextBuffer() { Init(); }
    wxRichTextBuffer( const wxRichTextBuffer& obj ): wxRichTextParagraphLayoutBox() { Init(); Copy( obj ); }
    virtual ~wxRichTextBuffer() ;

    wxCommandProcessor* GetCommandProcessor() const { return m_commandProcessor; }
    void SetStyleSheet( wxRichTextStyleSheet* styleSheet ) { m_styleSheet = styleSheet; }
    virtual wxRichTextStyleSheet* GetStyleSheet() const { return m_styleSheet; }
    bool SetStyleSheetAndNotify( wxRichTextStyleSheet* sheet );
    bool PushStyleSheet( wxRichTextStyleSheet* styleSheet );

    wxRichTextStyleSheet* PopStyleSheet();

    void Init();
    virtual void ResetAndClearCommands();
    virtual bool LoadFile( const wxString& filename, int type = wxRICHTEXT_TYPE_ANY );
    virtual bool SaveFile( const wxString& filename, int type = wxRICHTEXT_TYPE_ANY );
    virtual bool LoadFile( wxInputStream& stream, int type = wxRICHTEXT_TYPE_ANY );
    virtual bool SaveFile( wxOutputStream& stream, int type = wxRICHTEXT_TYPE_ANY );
    void SetHandlerFlags( int flags ) { m_handlerFlags = flags; }
    int GetHandlerFlags() const { return m_handlerFlags; }
    virtual wxRichTextRange AddParagraph( const wxString& text, wxTextAttrEx* paraStyle = NULL ) {
      Modify();
      return wxRichTextParagraphLayoutBox::AddParagraph( text, paraStyle );
    }

    virtual bool BeginBatchUndo( const wxString& cmdName );
    virtual bool EndBatchUndo();
    virtual bool BatchingUndo() const { return m_batchedCommandDepth > 0; }
    virtual bool SubmitAction( wxRichTextAction* action );
    virtual wxRichTextCommand* GetBatchedCommand() const { return m_batchedCommand; }
    virtual bool BeginSuppressUndo();
    virtual bool EndSuppressUndo();
    virtual bool SuppressingUndo() const { return m_suppressUndo > 0; }
    virtual bool CopyToClipboard( const wxRichTextRange& range );
    virtual bool PasteFromClipboard( long position );
    virtual bool CanPasteFromClipboard() const;
    virtual bool BeginStyle( const wxTextAttrEx& style );
    virtual bool EndStyle();
    virtual bool EndAllStyles();
    virtual void ClearStyleStack();
    virtual size_t GetStyleStackSize()
    const { return m_attributeStack.GetCount(); }
    bool BeginBold();
    bool EndBold() { return EndStyle(); }
    bool BeginItalic();
    bool EndItalic() { return EndStyle(); }
    bool BeginUnderline();
    bool EndUnderline() { return EndStyle(); }
    bool BeginFontSize( int pointSize );
    bool EndFontSize() { return EndStyle(); }
    bool BeginFont( const wxFont& font );
    bool EndFont() { return EndStyle(); }
    bool BeginTextColour( const wxColour& colour );
    bool EndTextColour() { return EndStyle(); }
    bool BeginAlignment( wxTextAttrAlignment alignment );
    bool EndAlignment() { return EndStyle(); }
    bool BeginLeftIndent( int leftIndent, int leftSubIndent = 0 );
    bool EndLeftIndent() { return EndStyle(); }
    bool BeginRightIndent( int rightIndent );
    bool EndRightIndent() { return EndStyle(); }
    bool BeginParagraphSpacing( int before, int after );
    bool EndParagraphSpacing() { return EndStyle(); }
    bool BeginLineSpacing( int lineSpacing );
    bool EndLineSpacing() { return EndStyle(); }
    bool BeginNumberedBullet( int bulletNumber, int leftIndent, int leftSubIndent,
                              int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC | wxTEXT_ATTR_BULLET_STYLE_PERIOD );
    bool EndNumberedBullet() { return EndStyle(); }
    bool BeginSymbolBullet( const wxString& symbol, int leftIndent,
                            int leftSubIndent, int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_SYMBOL );
    bool EndSymbolBullet() { return EndStyle(); }
    bool BeginStandardBullet( const wxString& bulletName, int leftIndent, int leftSubIndent,
                              int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_STANDARD );
    bool EndStandardBullet() { return EndStyle(); }
    bool BeginCharacterStyle( const wxString& characterStyle );
    bool EndCharacterStyle() { return EndStyle(); }
    bool BeginParagraphStyle( const wxString& paragraphStyle );
    bool EndParagraphStyle() { return EndStyle(); }
    bool BeginListStyle( const wxString& listStyle, int level = 1, int number = 1 );
    bool EndListStyle() { return EndStyle(); }
    bool BeginURL( const wxString& url, const wxString& characterStyle = wxEmptyString );
    bool EndURL() { return EndStyle(); }

    bool AddEventHandler( wxEvtHandler* handler );
    bool RemoveEventHandler( wxEvtHandler* handler, bool deleteHandler = false );
    void ClearEventHandlers();
    bool SendEvent( wxEvent& event, bool sendToAll = true );

    void Copy( const wxRichTextBuffer& obj );
    virtual wxRichTextObject* Clone() const { return new wxRichTextBuffer( *this ); }
    bool InsertParagraphsWithUndo( long pos, const wxRichTextParagraphLayoutBox& paragraphs, wxRichTextCtrl* ctrl, int flags = 0 );
    bool InsertTextWithUndo( long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags = 0 );
    bool InsertNewlineWithUndo( long pos, wxRichTextCtrl* ctrl, int flags = 0 );
    bool InsertImageWithUndo( long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl, int flags = 0 );
    bool DeleteRangeWithUndo( const wxRichTextRange& range, wxRichTextCtrl* ctrl );
    void Modify( bool modify = true ) { m_modified = modify; }
    bool IsModified() const { return m_modified; }

    wxRichTextAttr GetStyleForNewParagraph( long pos, bool caretPosition = false, bool lookUpNewParaStyle = false ) const;
    virtual void Dump();
    virtual void Dump( wxTextOutputStream& stream ) { wxRichTextParagraphLayoutBox::Dump( stream ); }
    static wxList& GetHandlers() { return sm_handlers; }    static void AddHandler( wxRichTextFileHandler *handler );
    static void InsertHandler( wxRichTextFileHandler *handler );
    static bool RemoveHandler( const wxString& name );
    static wxRichTextFileHandler *FindHandler( const wxString& name );
    static wxRichTextFileHandler *FindHandler( const wxString& extension, int imageType );
    static wxRichTextFileHandler *FindHandlerFilenameOrType( const wxString& filename, int imageType );
    static wxRichTextFileHandler *FindHandler( int imageType );

    static wxString GetExtWildcard( bool combine = false, bool save = false, wxArrayInt* types = NULL );
    static void CleanUpHandlers();
    static void InitStandardHandlers();
    static wxRichTextRenderer* GetRenderer() { return sm_renderer; }
    static void SetRenderer( wxRichTextRenderer* renderer );
    static int GetBulletRightMargin() { return sm_bulletRightMargin; }
    static void SetBulletRightMargin( int margin ) { sm_bulletRightMargin = margin; }
    static float GetBulletProportion() {
      return sm_bulletProportion;
    }
    static void SetBulletProportion( float prop ) { sm_bulletProportion = prop; }
    double GetScale() const {
      return m_scale;
    }
    void SetScale( double scale ) { m_scale = scale; }

  protected:
    wxCommandProcessor*     m_commandProcessor;
    bool                    m_modified;
    int                     m_batchedCommandDepth;
    wxString                m_batchedCommandsName;
    wxRichTextCommand*      m_batchedCommand;
    int                     m_suppressUndo;
    wxRichTextStyleSheet*   m_styleSheet;
    wxList                  m_eventHandlers;
    wxList                  m_attributeStack;
    int                     m_handlerFlags;
    static wxList           sm_handlers;
    static wxRichTextRenderer* sm_renderer;
    static int              sm_bulletRightMargin;
    static float            sm_bulletProportion;
    double                  m_scale;
};

enum wxRichTextCommandId {
  wxRICHTEXT_INSERT,
  wxRICHTEXT_DELETE,
  wxRICHTEXT_CHANGE_STYLE
};

class wxRichTextAction;
class wxRichTextCommand: public wxCommand {
  public:

    wxRichTextCommand( const wxString& name, wxRichTextCommandId id, wxRichTextBuffer* buffer,
                       wxRichTextCtrl* ctrl, bool ignoreFirstTime = false );
    wxRichTextCommand( const wxString& name );

    virtual ~wxRichTextCommand();

    bool Do();
    bool Undo();

    void AddAction( wxRichTextAction* action );
    void ClearActions();

    wxList& GetActions() { return m_actions; }

  protected:

    wxList  m_actions;
};

class wxRichTextAction: public wxObject {
  public:
    wxRichTextAction( wxRichTextCommand* cmd, const wxString& name, wxRichTextCommandId id, wxRichTextBuffer* buffer,
                      wxRichTextCtrl* ctrl, bool ignoreFirstTime = false );

    virtual ~wxRichTextAction();

    bool Do();
    bool Undo();
    void UpdateAppearance( long caretPosition, bool sendUpdateEvent = false,
                           wxArrayInt* optimizationLineCharPositions = NULL, wxArrayInt* optimizationLineYPositions = NULL );
    void ApplyParagraphs( const wxRichTextParagraphLayoutBox& fragment );
    void CalculateRefreshOptimizations( wxArrayInt& optimizationLineCharPositions, wxArrayInt& optimizationLineYPositions );
    wxRichTextParagraphLayoutBox& GetNewParagraphs() { return m_newParagraphs; }
    wxRichTextParagraphLayoutBox& GetOldParagraphs() { return m_oldParagraphs; }
    void SetPosition( long pos ) {
      m_position = pos;
    }
    long GetPosition() const { return m_position; }
    void SetRange( const wxRichTextRange& range ) { m_range = range; }
    const wxRichTextRange& GetRange() const { return m_range; }
    const wxString& GetName() const { return m_name; }

  protected:
    wxString                        m_name;
    wxRichTextBuffer*               m_buffer;
    wxRichTextCtrl*                 m_ctrl;
    wxRichTextParagraphLayoutBox    m_newParagraphs;
    wxRichTextParagraphLayoutBox    m_oldParagraphs;
    wxRichTextRange                 m_range;
    long                            m_position;
    bool                            m_ignoreThis;
    wxRichTextCommandId             m_cmdId;
};

#define wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET       0x0001
#define wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY    0x0010
#define wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES     0x0020
#define wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_BASE64    0x0040
#define wxRICHTEXT_HANDLER_NO_HEADER_FOOTER         0x0080
#define wxRICHTEXT_HANDLER_CONVERT_FACENAMES        0x0100

class wxRichTextFileHandler: public wxObject {
    DECLARE_CLASS( wxRichTextFileHandler )
  public:
    wxRichTextFileHandler( const wxString& name = wxEmptyString, const wxString& ext = wxEmptyString, int type = 0 )
      : m_name( name ), m_extension( ext ), m_type( type ), m_flags( 0 ), m_visible( true ) { }

    #if wxUSE_STREAMS
    bool LoadFile( wxRichTextBuffer *buffer, wxInputStream& stream ) { return DoLoadFile( buffer, stream ); }
    bool SaveFile( wxRichTextBuffer *buffer, wxOutputStream& stream ) { return DoSaveFile( buffer, stream ); }
    #endif

    bool LoadFile( wxRichTextBuffer *buffer, const wxString& filename );
    bool SaveFile( wxRichTextBuffer *buffer, const wxString& filename );
    virtual bool CanHandle( const wxString& filename ) const;
    virtual bool CanSave() const { return false; }
    virtual bool CanLoad() const { return false; }
    virtual bool IsVisible() const { return m_visible; }
    virtual void SetVisible( bool visible ) { m_visible = visible; }
    void SetName( const wxString& name ) { m_name = name; }
    wxString GetName() const { return m_name; }    void SetExtension( const wxString& ext ) { m_extension = ext; }
    wxString GetExtension() const { return m_extension; }    void SetType( int type ) { m_type = type; }
    int GetType() const { return m_type; }    void SetFlags( int flags ) { m_flags = flags; }
    int GetFlags() const { return m_flags; }    void SetEncoding( const wxString& encoding ) { m_encoding = encoding; }
    const wxString& GetEncoding() const { return m_encoding; }

  protected:

    #if wxUSE_STREAMS
    virtual bool DoLoadFile( wxRichTextBuffer *buffer, wxInputStream& stream ) = 0;
    virtual bool DoSaveFile( wxRichTextBuffer *buffer, wxOutputStream& stream ) = 0;
    #endif

    wxString  m_name;
    wxString  m_encoding;
    wxString  m_extension;
    int       m_type;
    int       m_flags;
    bool      m_visible;
};

class wxRichTextPlainTextHandler: public wxRichTextFileHandler {
    DECLARE_CLASS( wxRichTextPlainTextHandler )
  public:
    wxRichTextPlainTextHandler( const wxString& name = wxT( "Text" ), const wxString& ext = wxT( "txt" ),
                                int type = wxRICHTEXT_TYPE_TEXT )
      : wxRichTextFileHandler( name, ext, type ) { }    virtual bool CanSave() const { return true; }
    virtual bool CanLoad() const { return true; }
  protected:

    #if wxUSE_STREAMS
    virtual bool DoLoadFile( wxRichTextBuffer *buffer, wxInputStream& stream );
    virtual bool DoSaveFile( wxRichTextBuffer *buffer, wxOutputStream& stream );
    #endif

};

#if wxUSE_DATAOBJ

class wxRichTextBufferDataObject: public wxDataObjectSimple {
  public:
    wxRichTextBufferDataObject( wxRichTextBuffer* richTextBuffer = ( wxRichTextBuffer* ) NULL );
    virtual ~wxRichTextBufferDataObject();
    wxRichTextBuffer* GetRichTextBuffer();
    static const wxChar* GetRichTextBufferFormatId() { return ms_richTextBufferFormatId; }
    virtual wxDataFormat GetPreferredFormat( Direction dir ) const;
    virtual size_t GetDataSize() const;
    virtual bool GetDataHere( void *pBuf ) const;
    virtual bool SetData( size_t len, const void *buf );
    virtual size_t GetDataSize( const wxDataFormat& ) const { return GetDataSize(); }
    virtual bool GetDataHere( const wxDataFormat&, void *buf ) const { return GetDataHere( buf ); }
    virtual bool SetData( const wxDataFormat&, size_t len, const void *buf ) { return SetData( len, buf ); }

  private:
    wxDataFormat            m_formatRichTextBuffer;
    wxRichTextBuffer*       m_richTextBuffer;
    static const wxChar*    ms_richTextBufferFormatId;
};

#endif

class wxRichTextRenderer: public wxObject {
  public:
    wxRichTextRenderer() {}
    virtual ~wxRichTextRenderer() {}    virtual bool DrawStandardBullet( wxRichTextParagraph* paragraph, wxDC& dc,
        const wxTextAttrEx& attr, const wxRect& rect ) = 0;
    virtual bool DrawTextBullet( wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect,
                                 const wxString& text ) = 0;
    virtual bool DrawBitmapBullet( wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect ) = 0;
    virtual bool EnumerateStandardBulletNames( wxArrayString& bulletNames ) = 0;
};

class wxRichTextStdRenderer: public wxRichTextRenderer {
  public:
    wxRichTextStdRenderer() {}    virtual bool DrawStandardBullet( wxRichTextParagraph* paragraph, wxDC& dc,
        const wxTextAttrEx& attr, const wxRect& rect );
    virtual bool DrawTextBullet( wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr,
                                 const wxRect& rect, const wxString& text );
    virtual bool DrawBitmapBullet( wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect );
    virtual bool EnumerateStandardBulletNames( wxArrayString& bulletNames );
};

inline bool wxRichTextHasStyle( int flags, int style ) {
  return ( ( flags & style ) == style );
}
bool wxTextAttrEq( const wxTextAttrEx& attr1, const wxTextAttrEx& attr2 );
bool wxTextAttrEq( const wxTextAttr& attr1, const wxRichTextAttr& attr2 );
bool wxTextAttrEqPartial( const wxTextAttrEx& attr1, const wxTextAttrEx& attr2, int flags );
bool wxTextAttrEqPartial( const wxTextAttrEx& attr1, const wxRichTextAttr& attr2, int flags );
bool wxRichTextApplyStyle( wxTextAttrEx& destStyle, const wxTextAttrEx& style );
bool wxRichTextApplyStyle( wxRichTextAttr& destStyle, const wxTextAttrEx& style );
bool wxRichTextApplyStyle( wxTextAttrEx& destStyle, const wxRichTextAttr& style, wxRichTextAttr* compareWith = NULL );
bool wxRichTextApplyStyle( wxRichTextAttr& destStyle, const wxRichTextAttr& style, wxRichTextAttr* compareWith = NULL );
bool wxRichTextRemoveStyle( wxTextAttrEx& destStyle, const wxRichTextAttr& style );
bool wxRichTextCombineBitlists( int& valueA, int valueB, int& flagsA, int flagsB );
bool wxRichTextBitlistsEqPartial( int valueA, int valueB, int flags );
bool wxRichTextSplitParaCharStyles( const wxTextAttrEx& style, wxTextAttrEx& parStyle, wxTextAttrEx& charStyle );
bool wxRichTextTabsEq( const wxArrayInt& tabs1, const wxArrayInt& tabs2 );
void wxSetFontPreservingStyles( wxTextAttr& attr, const wxFont& font );
wxString wxRichTextDecimalToRoman( long n );

void wxRichTextModuleInit();

#endif
